﻿using log4net;
using log4net.Repository.Hierarchy;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using uid_t = System.Int64;

namespace ServerCommon.Log
{
    public class LogHelper
    {
        private const string RepositoryName = "DefaultRepository";
        private static log4net.Repository.ILoggerRepository _repository;

        private ILog _log;

        public bool IsFatalEnabled => _log.IsFatalEnabled;
        public bool IsWarnEnabled => _log.IsWarnEnabled;
        public bool IsInfoEnabled => _log.IsInfoEnabled;
        public bool IsDebugEnabled => _log.IsDebugEnabled;
        public bool IsErrorEnabled => _log.IsErrorEnabled;

        private static long _beginTick = 1;// DateTime.Now.Ticks;

        public enum EnumContextScopeType
        {
            Global,
            Thread,
            Logical,
        }

        public static void Init(string configFile, bool watch, string folderName, string fileName)
        {
            // 设置log flush time out时间，每次flush的间隔 最大不会超过这个时间
            LogManager.Flush(5000); // 定义成10秒 考虑应该配置在哪里

            _repository = LogManager.CreateRepository(RepositoryName);
            GlobalContext.Properties["FolderName"] = folderName;
            GlobalContext.Properties["FileName"] = fileName;

            if (watch)
            {
                log4net.Config.XmlConfigurator.ConfigureAndWatch(_repository, new FileInfo(configFile));
            }
            else
            {
                log4net.Config.XmlConfigurator.Configure(_repository, new FileInfo(configFile));
            }

            GlobalContext.Properties["ProcessState"] = string.Empty;
            GlobalContext.Properties["SerialNumber"] = string.Empty;

            MarkSerialNumber();
        }

        public static void Release()
        {
            LogManager.Shutdown();
        }

        public static LogHelper GetLogger(Type type)
        {
            return new LogHelper
            {
                _log = LogManager.GetLogger(RepositoryName, type)
            };
        }

        public static LogHelper GetLogger(string name)
        {
            return new LogHelper
            {
                _log = LogManager.GetLogger(RepositoryName, name)
            };
        }

        public void Info(object msg)
        {
            if (!IsInfoEnabled)
            {
                return;
            }
            _log.Info(msg);
        }

        public void Info(object msg, Exception ex)
        {
            if (!IsInfoEnabled)
            {
                return;
            }
            _log.Info(msg, ex);
        }

        public void InfoFormat(string fmt, object arg0)
        {
            if (!IsInfoEnabled)
            {
                return;
            }
            _log.InfoFormat(fmt, arg0);
        }

        public void InfoFormat(string fmt, object arg0, object arg1)
        {
            if (!IsInfoEnabled)
            {
                return;
            }
            _log.InfoFormat(fmt, arg0, arg1);
        }

        public void InfoFormat(string fmt, object arg0, object arg1, object arg2)
        {
            if (!IsInfoEnabled)
            {
                return;
            }
            _log.InfoFormat(fmt, arg0, arg1, arg2);
        }

        public void InfoFormat(string fmt, params object[] args)
        {
            if (!IsInfoEnabled)
            {
                return;
            }
            _log.InfoFormat(fmt, args);
        }

        public void Debug(object msg)
        {
            if (!IsDebugEnabled)
            {
                return;
            }
            _log.Debug(msg);
        }

        public void Debug(object msg, Exception ex)
        {
            if (!IsDebugEnabled)
            {
                return;
            }
            _log.Debug(msg, ex);
        }

        public void DebugFormat(string fmt, object arg0)
        {
            if (!IsDebugEnabled)
            {
                return;
            }
            _log.DebugFormat(fmt, arg0);
        }

        public void DebugFormat(string fmt, object arg0, object arg1)
        {
            if (!IsDebugEnabled)
            {
                return;
            }
            _log.DebugFormat(fmt, arg0, arg1);
        }

        public void DebugFormat(string fmt, object arg0, object arg1, object arg2)
        {
            if (!IsDebugEnabled)
            {
                return;
            }
            _log.DebugFormat(fmt, arg0, arg1, arg2);
        }

        public void DebugFormat(string fmt, params object[] args)
        {
            if (!IsDebugEnabled)
            {
                return;
            }
            _log.DebugFormat(fmt, args);
        }

        public void Warn(object msg)
        {
            if (!IsWarnEnabled)
            {
                return;
            }
            _log.Warn(msg);
        }

        public void Warn(object msg, Exception ex)
        {
            if (!IsWarnEnabled)
            {
                return;
            }
            _log.Warn(msg, ex);
        }

        public void WarnFormat(string fmt, object arg0)
        {
            if (!IsWarnEnabled)
            {
                return;
            }
            _log.WarnFormat(fmt, arg0);
        }

        public void WarnFormat(string fmt, object arg0, object arg1)
        {
            if (!IsWarnEnabled)
            {
                return;
            }
            _log.WarnFormat(fmt, arg0, arg1);
        }

        public void WarnFormat(string fmt, object arg0, object arg1, object arg2)
        {
            if (!IsWarnEnabled)
            {
                return;
            }
            _log.WarnFormat(fmt, arg0, arg1, arg2);
        }

        public void WarnFormat(string fmt, params object[] args)
        {
            if (!IsWarnEnabled)
            {
                return;
            }
            _log.WarnFormat(fmt, args);
        }

        public void Error(object msg)
        {
            if (!IsErrorEnabled)
            {
                return;
            }
            _log.Error(msg);
        }

        public void Error(object msg, Exception ex)
        {
            if (!IsErrorEnabled)
            {
                return;
            }
            _log.Error(msg, ex);
        }

        public void ErrorFormat(string fmt, object arg0)
        {
            if (!IsErrorEnabled)
            {
                return;
            }
            _log.ErrorFormat(fmt, arg0);
        }

        public void ErrorFormat(string fmt, object arg0, object arg1)
        {
            if (!IsErrorEnabled)
            {
                return;
            }
            _log.ErrorFormat(fmt, arg0, arg1);
        }

        public void ErrorFormat(string fmt, object arg0, object arg1, object arg2)
        {
            if (!IsErrorEnabled)
            {
                return;
            }
            _log.ErrorFormat(fmt, arg0, arg1, arg2);
        }

        public void ErrorFormat(string fmt, params object[] args)
        {
            if (!IsErrorEnabled)
            {
                return;
            }
            _log.ErrorFormat(fmt, args);
        }

        public void Fatal(object msg)
        {
            if (!IsFatalEnabled)
            {
                return;
            }
            _log.Fatal(msg);
        }

        public void Fatal(object msg, Exception ex)
        {
            if (!IsFatalEnabled)
            {
                return;
            }
            _log.Fatal(msg, ex);
        }

        public static void MarkSerialNumber(EnumContextScopeType scopeType = EnumContextScopeType.Thread)
        {
            _beginTick++;
            switch (scopeType)
            {
                case EnumContextScopeType.Global:
                    log4net.GlobalContext.Properties["SerialNumber"] = _beginTick;// ms.ToString();
                    break;
                case EnumContextScopeType.Logical:
                    log4net.LogicalThreadContext.Properties["SerialNumber"] = _beginTick;// ms.ToString();
                    break;
                case EnumContextScopeType.Thread:
                    log4net.ThreadContext.Properties["SerialNumber"] = _beginTick;// ms.ToString();
                    break;
            }
        }
    }
}
